package org.afk.sisy.io;

import java.io.*;
import java.nio.file.*;
import java.text.*;
import java.util.*;

import org.afk.sisy.*;
import org.afk.tools.log.*;

public class Attic
{
	private final SisyJob job;

	private final ErrorHandler errorHandler;
	private final SisyProgress progress;

	public Attic(final SisyJob job, final ErrorHandler errorHandler, final SisyProgress progress)
	{
		super();
		this.job = job;
		this.errorHandler = errorHandler;
		this.progress = progress;
	}

	private Path createDirectory(final Path targetPath)
	{
		try
		{
			return Files.createDirectories(targetPath);
		}
		catch (final IOException e)
		{
			this.errorHandler.warning("Could not create " + targetPath);
			return null;
		}
	}

	private Path createSISYname(final Path targetPath)
	{
		return targetPath.getParent().resolve(targetPath.getFileName() + "." + formatTime() + "." + SisyConstants.FILE_SUFFIX);
	}

	private String formatTime()
	{
		return new SimpleDateFormat("yyyy.MM.dd-HH.mm.ss").format(new Date());
	}

	private boolean deleteChanged(final Path old)
	{
		final StopWatch watch = new StopWatch();
		if (Files.exists(old))
			try
			{
				Files.delete(old);
				this.progress.incDeleted(1);
				this.errorHandler.info("Deleted " + old + " " + watch);
				return true;
			}
			catch (final IOException e)
			{
				this.errorHandler.warning("Could not delete " + old, e);
				progress.incError(1);
				return false;
			}
		return true;
	}

	private boolean moveToAttic(final PathWrapper source, final Path dest)
	{
		final StopWatch watch = new StopWatch();
		if (createDirectory(dest.getParent()) == null)
		{
			this.errorHandler.warning("Could not create " + dest.getParent() + " " + watch);
			progress.incError(1);
			return false;
		}

		try
		{
			if (Files.move(source.getAbsolutPath(), createSISYname(dest), StandardCopyOption.COPY_ATTRIBUTES) != null)
			{
				this.progress.incStoredInAtticCount(1);
				this.errorHandler.info("In Attic " + source + " " + watch);
				return true;
			}
			else
			{
				this.errorHandler.warning("Could not attic " + source + " " + watch);
				progress.incError(1);
				return false;
			}
		}
		catch (final IOException | UnsupportedOperationException e)
		{
			this.errorHandler.warning("Could not attic " + source + " " + watch, e);
			progress.incError(1);
			return false;
		}
	}

	private boolean renameAttic(final Path old) throws IOException
	{
		final boolean success = Files.move(old, createSISYname(old)) != null;
		if (!success)
		{
			this.errorHandler.warning("Could not rename " + old);
			progress.incError(1);
		}

		return success;
	}

	public boolean store(final PathWrapper old) throws IOException
	{
		if (old.isDirectory())
			return true; // not supported. directories are not for attic 

		if (this.job.getAtticOption() == AtticOption.MOVE)
			if (this.job.getAtticDir() != null)
				return moveToAttic(old, createAtticFile(old));
			else
				return renameAttic(old.getAbsolutPath());
		else if (this.job.getAtticOption() == AtticOption.DELETE)
			return deleteChanged(old.getAbsolutPath());
		else if (this.job.getAtticOption() == AtticOption.RENAME)
			return renameAttic(old.getAbsolutPath());
		return false;
	}

	private Path createAtticFile(final PathWrapper old)
	{
		return this.job.getAtticDir().resolve(old.getRelativePath());
	}

}
